﻿using System;
using System.IO;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Deployment;

namespace Lapointe.WebPartPageHistory.ListEventReceivers
{
    internal class OtbHistory : IHistory
    {
        /// <summary>
        /// Exports the specified item.
        /// </summary>
        /// <param name="sourceItem">The source item.</param>
        /// <param name="directory">The directory to store the exported data.</param>
        /// <param name="includeDependencies">if set to <c>true</c> include dependencies such as page layouts, master pages, and/or images, etc.</param>
        public void Export(SPListItem sourceItem, string directory, bool includeDependencies)
        {
            string filename = directory + "\\item.bak";
            const bool compressFile = true;
            const bool overwrite = true;
            const bool quiet = true;
            const bool haltOnWarning = false;
            const bool haltOnFatalError = true;
            const bool includeusersecurity = false;
            const bool logFile = false;
            const int cabSize = 0;
            const SPIncludeVersions versions = SPIncludeVersions.CurrentVersion;
            SPIncludeDescendants includeDescendants = (includeDependencies
                                                           ? SPIncludeDescendants.All
                                                           : SPIncludeDescendants.None);

            SPExportSettings settings = new SPExportSettings();
            SPExport export = new SPExport(settings);

            SetupExportObjects(settings, includeDependencies, cabSize, compressFile, filename, haltOnFatalError, haltOnWarning, includeusersecurity, logFile, overwrite, quiet, versions);

            PerformExport(sourceItem.ParentList, export, settings, includeDescendants, sourceItem.UniqueId);
        }

        /// <summary>
        /// Imports the specified item.
        /// </summary>
        /// <param name="sourceItem">The source item.</param>
        /// <param name="directory">The directory containing the data to import.</param>
        public void Import(SPListItem sourceItem, string directory)
        {
            // The deployment API requires that the page be checked in so that the web part changes can be applied.
            bool checkedOut = false;
            if (sourceItem.File.CheckOutStatus != SPFile.SPCheckOutStatus.None)
            {
                checkedOut = true;
                sourceItem.File.UndoCheckOut();
            }

            string filename = directory + "\\item.bak";
            const bool compressFile = true;
            const bool quiet = true;
            const bool haltOnWarning = false;
            const bool haltOnFatalError = true;
            const bool includeusersecurity = false;
            const bool logFile = true;
            const bool retainObjectIdentity = true;

            const SPUpdateVersions updateVersions = SPUpdateVersions.Append;

            SPImportSettings settings = new SPImportSettings();
            SPImport import = new SPImport(settings);

            SetupImportObject(settings, compressFile, filename, haltOnFatalError, haltOnWarning,
                                           includeusersecurity, logFile, quiet, updateVersions,
                                           retainObjectIdentity);

            PerformImport(sourceItem.ParentList, import, settings);

            if (checkedOut)
                sourceItem.File.CheckOut();
        }

        #region Import Helpers

        /// <summary>
        /// Performs the import.
        /// </summary>
        /// <param name="list">The list to import into.</param>
        /// <param name="import">The import object.</param>
        /// <param name="settings">The settings object.</param>
        private static void PerformImport(SPList list, SPImport import, SPImportSettings settings)
        {
            SPSite site = list.ParentWeb.Site;
            settings.SiteUrl = site.MakeFullUrl(list.ParentWebUrl);

            import.Run();
        }

        /// <summary>
        /// Sets up the import object.
        /// </summary>
        /// <param name="settings">The settings.</param>
        /// <param name="compressFile">if set to <c>true</c> [compress file].</param>
        /// <param name="filename">The filename.</param>
        /// <param name="haltOnFatalError">if set to <c>true</c> [halt on fatal error].</param>
        /// <param name="haltOnWarning">if set to <c>true</c> [halt on warning].</param>
        /// <param name="includeusersecurity">if set to <c>true</c> [includeusersecurity].</param>
        /// <param name="logFile">if set to <c>true</c> [log file].</param>
        /// <param name="quiet">if set to <c>true</c> [quiet].</param>
        /// <param name="updateVersions">The update versions.</param>
        /// <param name="retainObjectIdentity">if set to <c>true</c> [retain object identity].</param>
        private static void SetupImportObject(SPImportSettings settings, bool compressFile, string filename, bool haltOnFatalError, bool haltOnWarning, bool includeusersecurity, bool logFile, bool quiet, SPUpdateVersions updateVersions, bool retainObjectIdentity)
        {
            settings.CommandLineVerbose = !quiet;
            settings.HaltOnNonfatalError = haltOnFatalError;
            settings.HaltOnWarning = haltOnWarning;
            settings.FileCompression = compressFile;

            if (!compressFile)
            {
                if (string.IsNullOrEmpty(filename) || !Directory.Exists(filename))
                {
                    throw new SPException(SPResource.GetString("DirectoryNotFoundExceptionMessage", new object[] { filename }));
                }
            }
            else if (string.IsNullOrEmpty(filename) || !File.Exists(filename))
            {
                throw new SPException(SPResource.GetString("FileNotFoundExceptionMessage", new object[] { filename }));
            }

            if (!compressFile)
            {
                settings.FileLocation = filename;
            }
            else
            {
                string fileLocation = Path.GetDirectoryName(filename);
                filename = Path.GetFileName(filename);
                settings.FileLocation = fileLocation;
                settings.BaseFileName = filename;
            }

            if (logFile)
            {
                if (!compressFile)
                {
                    settings.LogFilePath = Path.Combine(settings.FileLocation, "import.log");
                }
                else
                    settings.LogFilePath = Path.Combine(settings.FileLocation, filename + ".import.log");
            }


            if (includeusersecurity)
            {
                settings.IncludeSecurity = SPIncludeSecurity.All;
                settings.UserInfoDateTime = SPImportUserInfoDateTimeOption.ImportAll;
            }
            settings.UpdateVersions = updateVersions;
            settings.RetainObjectIdentity = retainObjectIdentity;
        }

        #endregion

        #region Export Helper

        /// <summary>
        /// Performs the export.
        /// </summary>
        /// <param name="list">The list.</param>
        /// <param name="export">The export.</param>
        /// <param name="settings">The settings.</param>
        /// <param name="includeDescendants">The include descendants.</param>
        /// <param name="uniqueItemId">The unique item id.</param>
        private static void PerformExport(SPList list, SPExport export, SPExportSettings settings, SPIncludeDescendants includeDescendants, Guid uniqueItemId)
        {
            SPSite site = list.ParentWeb.Site;
            settings.SiteUrl = site.MakeFullUrl(list.ParentWebUrl);

            SPExportObject exportObject = new SPExportObject();
            exportObject.IncludeDescendants = includeDescendants;
            exportObject.Type = SPDeploymentObjectType.ListItem;
            exportObject.Id = uniqueItemId;
            settings.ExportObjects.Add(exportObject);

            export.Run();
        }

        /// <summary>
        /// Sets up the export objects.
        /// </summary>
        /// <param name="settings">The settings.</param>
        /// <param name="includeDependencies">if set to <c>true</c> [include dependencies].</param>
        /// <param name="cabSize">Size of the CAB.</param>
        /// <param name="compressFile">if set to <c>true</c> [compress file].</param>
        /// <param name="filename">The filename.</param>
        /// <param name="haltOnFatalError">if set to <c>true</c> [halt on fatal error].</param>
        /// <param name="haltOnWarning">if set to <c>true</c> [halt on warning].</param>
        /// <param name="includeUserSecurity">if set to <c>true</c> [include user security].</param>
        /// <param name="logFile">if set to <c>true</c> [log file].</param>
        /// <param name="overwrite">if set to <c>true</c> [overwrite].</param>
        /// <param name="quiet">if set to <c>true</c> [quiet].</param>
        /// <param name="versions">The versions.</param>
        private static void SetupExportObjects(SPExportSettings settings, bool includeDependencies, int cabSize, bool compressFile, string filename, bool haltOnFatalError, bool haltOnWarning, bool includeUserSecurity, bool logFile, bool overwrite, bool quiet, SPIncludeVersions versions)
        {
            if (compressFile)
            {
                if (!Directory.Exists(Path.GetDirectoryName(filename)))
                    Directory.CreateDirectory(Path.GetDirectoryName(filename));
            }
            if (!overwrite && File.Exists(filename))
                throw new SPException(SPResource.GetString("NotOverwriteExportError", new object[] { filename }));

            settings.ExportMethod = SPExportMethodType.ExportAll;
            settings.HaltOnNonfatalError = haltOnFatalError;
            settings.HaltOnWarning = haltOnWarning;
            settings.CommandLineVerbose = !quiet;
            settings.IncludeVersions = versions;
            settings.IncludeSecurity = includeUserSecurity ? SPIncludeSecurity.All : SPIncludeSecurity.None;
            settings.OverwriteExistingDataFile = overwrite;
            settings.FileMaxSize = cabSize;
            settings.FileCompression = compressFile;
            settings.ExcludeDependencies = !includeDependencies;
            settings.FileLocation = filename;
            if (!compressFile)
            {
                settings.FileLocation = filename;
            }
            else
            {
                string fileLocation = Path.GetDirectoryName(filename);
                filename = Path.GetFileName(filename);
                settings.FileLocation = fileLocation;
                settings.BaseFileName = filename;
            }

            if (logFile)
            {
                if (!compressFile)
                {
                    settings.LogFilePath = Path.Combine(settings.FileLocation, "export.log");
                }
                else
                {
                    settings.LogFilePath = Path.Combine(settings.FileLocation, filename + ".export.log");
                }
                bool fileExists = File.Exists(settings.LogFilePath);
                if (!overwrite && fileExists)
                {
                    throw new SPException(SPResource.GetString("DataFileExists", new object[] { settings.LogFilePath }));
                }
                if (fileExists)
                {
                    File.Delete(settings.LogFilePath);
                }
            }
        }

        #endregion

    }

}
